/*!
  \class Branch
  \brief Gałąź ronda, czyli jedna ulica.

  Obiekt gałęzi odpowiada ulicy dochodzącej do obręczy ronda. Nie dziedziczy po QGraphicsItem gdyż stanowi jedynie tło dla samochodów.
  Gałąź jest <b>zawsze</b> jednokierunkowa. Aby osiągnąć jezdnię dwukierunkową, można wykorzystać mechanizm zależności (\link types.h::Dependence Dependence \endlink) między gałęziami.
  Oprócz danych niezbędnych do narysowania gałęzi (_fi, _laneWidth, _numLanes, _hasZebra), gałąź zawiera informacje na temat częstości nadjeżdżania samochodów i przechodzenia pieszych (wykorzystywane przez RSim::generator()).
  Obiekt ten jest przygotowany do zaimplementowania funkcjonalności dynamicznej zmiany odchylenia przez użytkownika. Rysuje się sam (Branch::draw()) za każdym razem odczytując wartość zmiennej _fi.

*/

#include "branch.h"
#include <QPainter>
#include <QDebug>
#include <iostream>
#include <QBrush>
class QWidget;

using namespace std;
/**
@brief Jedyny konstruktor

@param x Liczba pasów gałęzi
@param y Kierunek (outlet lub entry, czyli wjazd lub zjazd)
@param fi Kąt odchylenia (potrzebny do rysowania)
@param laneWidth Szerokość jednego pasa (powinna być taka sama, jak na rondzie)
\param freq Częstość zjawiania się samochodów na tej gałęzi
\param hasZebra Czy należy rysować pasy i generować pieszych na tej gałęzi
*/
Branch::Branch(int x, Direction y, qreal fi, qreal laneWidth, int freq, bool hasZebra)
    :_direction(y), _numLanes(x), _fi(fi), _laneWidth(laneWidth),
    _frequencySpan(freq), _hasZebra(hasZebra),
    _zebraIntensity(0), _zebraIntensityUsed(true), _counter(0)
{

}

void Branch::zebraIntensityUsed()
{    _zebraIntensityUsed = true; }

/*! \brief Funkcja dla klasy RSim do sprawdzenia częstości generowania pieszych.

    Ponieważ bardzo źle wyglądają piesi przechodzący przez jezdnię pojedynczo co x sekund ze szwajcarską regularnością, została wprowadzona ta funkcja. Zwraca ona wartość z zakresu < 0.8 * _zebraIntensity, 1.2 * _zebraIntensity >, dzięki czemu piesi zachowują się nieco naturalniej.
    Flaga _zebraIntensityUsed powinna być podniesiona przez RSim, jak tylko stworzy on pieszego dzięki zwróconej mu wartości.
*/
int Branch::getZebraIntensity()
{
    if (_zebraIntensityUsed)
    {
        if (_zebraIntensity == 0)
            return 0;
        int variation = int(_zebraIntensity * 0.4);
        variation = variation ? variation : 1;  // nie może być zerem
        int rand = qrand()%variation;
        rand -= variation/2;
        _zebraRandomIntensity = _zebraIntensity + rand;
    }
    return _zebraRandomIntensity;
}

/**
@brief Podstawowa funkcja rysująca gałąź

Zwykła gałąź to tak naprawdę prostokąt z kreskami na sobie (linie oddzielające pasy). Zatem aby go narysować można przekręcić planszę o jego kąt odchylenia, narysować potrzebne elementy i odkręcic planszę z powrotem. Gałąź ciągnie się na odległość 10000 pikseli - y.
@param painter Obiekt QPainter - rysuje.
@param radius Odległość od środka ronda. Od tej odległości zaczyna się gałąź.
*/
void Branch::draw(QPainter *painter, qreal radius) const // y = radius - szerokośćObręczy/2
{
    // przekręcić planszę o fi stopni
    /* narysować prostokąt ABCD.
       A = (-getWidth()/2, radius - szerokośćObręczy/2);
       B = (getWidth()/2, radius - szerokośćObręczy/2);
       C i D => trzeba wymyśleć jakiś limit igrekowy.
       */
    // odkręcić planszę z powrotem.
    painter->rotate(_fi);
    qreal y = radius - (_laneWidth) + 1;

    QBrush brush;
    brush.setStyle(Qt::SolidPattern);
    brush.setColor(QColor(0,0,0));     // czarny kolor
    if (_direction == entry)
        brush.setColor(QColor(64, 64, 64));
    painter->setBrush(brush);
    painter->setPen(Qt::NoPen);
    int x = (_numLanes * _laneWidth) / 2;
    painter->drawRect(QRectF(-x, y, 2*x, 10000));

    // jeszcze linie przerywane;
    painter->setBrush(Qt::NoBrush);        // bez wypełnienia
    painter->setPen(QPen(Qt::white, 2, Qt::DashLine, Qt::FlatCap, Qt::RoundJoin)); // biala przerywana

    for (int i = 1; i < _numLanes; i++)
        painter->drawLine(-x + i * _laneWidth, y + _laneWidth, -x + i * _laneWidth, 3000);

    if (_hasZebra)
    {
        // spróbujmy narysować prostokąt o paskowanym wypełnienu.
        painter->setPen(Qt::NoPen);
        brush.setTexture(QPixmap(":/images/pasy.png"));
        painter->setBrush(brush);
        painter->drawRect(QRectF(-x, radius, 2*x, _laneWidth * 1));
    }

    painter->rotate(-_fi);
}

/**
@brief Przeładowana funkcja rysująca do połączonych (glued) gałęzi

Tam gdzie miał być sąsiad, rysujemy ulicę o liczbie pasów równej sumie "naszej" gałęzi i sąsiada. Oddzielamy je podwójną linią ciągłą.
Gałąź ciągnie się na odległość 10000 pikseli - y.
@param painter Obiekt QPainter - rysuje.
@param radius Odległość od środka ronda.
@param neighbour Wskaźnik na gałąź, z którą jesteśmy połączeni
@see void draw(QPainter *painter, int y)
*/
void Branch::draw(QPainter *painter, qreal radius, const Branch* neighbour) const
{
    painter->rotate(neighbour->getFi());
    //qDebug() << _fi << "   " << neighbour->getFi() << endl;

    qreal y = radius - (_laneWidth) + 1;
    QBrush brush;
    brush.setStyle(Qt::SolidPattern);
    brush.setColor(QColor(0,0,0));     // czarny kolor
    painter->setBrush(brush);
    painter->setPen(Qt::NoPen);
    int x = ((_numLanes + neighbour->getNumLanes())* _laneWidth) / 2;  // połowa szerokości całości
    painter->drawRect(QRectF(-x, y, 2*x, 10000));

    painter->setBrush(Qt::NoBrush);        // bez wypełnienia
    painter->setPen(QPen(Qt::white, 2, Qt::DashLine, Qt::FlatCap, Qt::RoundJoin)); // biala przerywana

    for (int i = 1; i < neighbour->getNumLanes(); i++)
        painter->drawLine(QLineF(-x + i * _laneWidth, y + _laneWidth, -x + i * _laneWidth, 10000));
    // no to mamy przerywane na pierwszej gałęzi...
    for (int i = neighbour->getNumLanes() + 1; i < _numLanes + neighbour->getNumLanes(); i++)
        painter->drawLine(QLineF(-x + i * _laneWidth, y + _laneWidth, -x + i * _laneWidth, 10000));
    // mamy przerywane na drugiej gałęzi...
    painter->setPen(QPen(Qt::white, 1, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin)); // ciągła
    painter->drawLine(QLineF(-x +neighbour->getNumLanes()*_laneWidth-1, y + _laneWidth, -x +neighbour->getNumLanes()*_laneWidth-1, 10000));
    painter->drawLine(QLineF(-x +neighbour->getNumLanes()*_laneWidth+1, y + _laneWidth, -x +neighbour->getNumLanes()*_laneWidth+1, 10000));

    if (_hasZebra)
    {
        // spróbujmy narysować prostokąt o paskowanym wypełnienu.
        painter->setPen(Qt::NoPen);
        brush.setTexture(QPixmap(":/images/pasy.png"));
        painter->setBrush(brush);
        painter->drawRect(-x, radius, 2*x, _laneWidth * 1);
    }

    painter->rotate(-neighbour->getFi());
}

void Branch::setNumLanes(int x)
{    _numLanes = x;     }
void Branch::setLaneWidth(qreal laneWidth)
{   _laneWidth = laneWidth; }
void Branch::setDirection(Direction x)
{    _direction = x;    }
void Branch::setFi(qreal fi)
{    _fi = fi;    }
void Branch::setTrafficDistribution(int index, int value)
{    _trafficDistribution[index] = value; }
void Branch::setZebra(bool z)
{   _hasZebra = z; }
void Branch::setFrequency(int value)
{
    if (value > 100)
        value = 100;
    if (value < 0)
        value = 0;
    _frequencySpan = value;
}
void Branch::setZebraIntensity(int value)
{    _zebraIntensity = value;/* qDebug() << this << "zebra set" << value;*/  }

/*! Funkcja ułatwiająca życie: ustawia wszystkie wartości w _trafficDistribution na zero */
void Branch::clearTrafficDistribution()
{
    for (int i = 0; i < _trafficDistribution.size(); i++)
        _trafficDistribution[i] = 0;
}

int Branch::getNumLanes() const
{    return _numLanes;  }
Direction Branch::getDirection() const
{    return _direction; }
qreal Branch::getWidth() const
{    return (_laneWidth * _numLanes);   }
qreal Branch::getFi() const
{    return _fi;    }
qreal Branch::getLaneWidth() const
{    return _laneWidth; }
QList<int> *Branch::getTrafficDistribution()
{    return &_trafficDistribution; }
int Branch::getFrequency() const
{   return (_frequencySpan); }
bool Branch::getZebra() const
{   return _hasZebra; }
int Branch::getRealZebraIntensity() const
{   return _zebraIntensity; }
